package com.lagou.edu.factory;

import com.alibaba.druid.util.StringUtils;
import com.lagou.edu.annotation.Autowired;
import com.lagou.edu.annotation.Service;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.reflections.Reflections;

import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.*;


public class BeanFactory {

    //IOC容器对象
    private static Map<String, Object> map = new HashMap<>();
    //缓存对象依赖关系Map
    private static Map<String, List<Class<?>>> relationMap = new HashMap<>();//accountDao --> [ConnectionUtils]
    //对外提供获取实例对象的接口（根据id获取）
    public static Object getBean(String id) {
        return map.get(id);
    }
    //获取配置的事务管理器标志
    private static String transactionManagerSign = "";
    public static String getTransactionManager() { return transactionManagerSign;}


   static {
        //读取XML配置文件
        InputStream resourceAsStream = BeanFactory.class.getClassLoader().getResourceAsStream("applicationContext.xml");
        try {
            //解析XML
            Document document = new SAXReader().read(resourceAsStream);
            Element rootElement = document.getRootElement();
            List<Element> elements = rootElement.elements();

            for (Element element : elements) {
                String name = element.getName();
                //获得需要扫面的包
                if (name.equals("component-scan")) {
                    String packageName = element.attributeValue("base-package");
                    //加载对象，并获取对象注入关系
                    createObject(packageName);
                }
                //是否需要开启事务
                if (name.equals("annotation-driven")) {
                    String transaction = element.attributeValue("transaction-manager");
                    transactionManagerSign = transaction;
                }
            }
            //处理对象注入关系
            ObjectAutowiredRelation();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    //扫描指定注解获得对象
    private static void createObject(String packageName) throws Exception {

        Reflections reflections = new Reflections(packageName);
        //获取Service注解类
        Set<Class<?>> clazzSet = reflections.getTypesAnnotatedWith(Service.class);
        for (Class<?> clazz : clazzSet) {
            //获取该类的注解
            Service annotation = clazz.getAnnotation(Service.class);
            //判断注解是否有value值，有值用value作为id，无值用类名做id
            String id;
            if (StringUtils.isEmpty(annotation.value())) {
                //简易类名
                String name = clazz.getSimpleName();
                //类名首字母小写作为id
                id = getStr(name);
            } else {
                id = annotation.value();
            }
            map.put(id, clazz.newInstance());

            //获取所有的属性
                Field[] fields = clazz.getDeclaredFields();
                for (Field field : fields) {
                    Autowired autowired = field.getAnnotation(Autowired.class);
                    //属性上有Autowired注解
                    if(null != autowired){
                        //将属性放入缓存map
                        List<Class<?>> objects = relationMap.get(id);
                        if(null==objects){
                            objects = new ArrayList<>();
                        }
                        objects.add(field.getType());
                        relationMap.put(id,objects);
                    }
            }

        }


    }

    //首字母小写
    private static String getStr(String str) {
        char[] chars = new char[1];
        chars[0] = str.charAt(0);
        String temp = new String(chars);
        if (chars[0] >= 'A' && chars[0] <= 'Z') {
            return str.replaceFirst(temp, temp.toLowerCase());
        }

        return str;
    }

    //处理对象注入关系
    private static void ObjectAutowiredRelation() throws IllegalAccessException, InstantiationException {
        if(null!=relationMap){
            Set<Map.Entry<String, List<Class<?>>>> entries = relationMap.entrySet();
            for (Map.Entry<String, List<Class<?>>> entry : entries) {
                //获取对象
                Object object = map.get(entry.getKey());
                //对象属性
                Field[] fields = object.getClass().getDeclaredFields();
                for (Field field : fields) {
                    for (Class<?> aClass : entry.getValue()) {
                        if(field.getType() == aClass){
                            //开启访问权限
                            field.setAccessible(true);
                            //获取该属性类名
                            String simpleName = aClass.getSimpleName();
                            //首字母小写
                            String str = getStr(simpleName);
                            //从容器中找出对象为该属性注入值
                            field.set(object,map.get(str));
                        }
                    }
                }
                map.put(entry.getKey(),object);
            }
        }
    }
}



